import '../../../style/morebox.css';
import { BasePlayer } from '../../player/BasePlayer';
import { TextControlMessage } from '../../controlMessage/TextControlMessage';
import { CommandControlMessage } from '../../controlMessage/CommandControlMessage';
import { ControlMessage } from '../../controlMessage/ControlMessage';
import Size from '../../Size';
import DeviceMessage from '../DeviceMessage';
import VideoSettings from '../../VideoSettings';
import { StreamClientScrcpy } from '../client/StreamClientScrcpy';

const TAG = '[GoogMoreBox]';

export class GoogMoreBox {
	private static defaultSize = new Size(480, 480);
	private onStop ?: () => void;
	private readonly holder : HTMLElement;
	private readonly input : HTMLTextAreaElement;
	private readonly bitrateInput ?: HTMLInputElement;
	private readonly maxFpsInput ?: HTMLInputElement;
	private readonly iFrameIntervalInput ?: HTMLInputElement;
	private readonly maxWidthInput ?: HTMLInputElement;
	private readonly maxHeightInput ?: HTMLInputElement;

	constructor(udid : string, private player : BasePlayer, private client : StreamClientScrcpy) {
		const playerName = player.getName();
		const videoSettings = player.getVideoSettings();
		const { displayId } = videoSettings;
		const preferredSettings = player.getPreferredVideoSetting();
		const moreBox = document.createElement('div');
		moreBox.className = 'more-box';
		const nameBox = document.createElement('p');
		nameBox.innerText = `${udid} (${playerName})`;
		nameBox.className = 'text-with-shadow';
		moreBox.appendChild(nameBox);
		const input = (this.input = document.createElement('textarea'));
		input.classList.add('text-area');
		const sendButton = document.createElement('button');
		sendButton.innerText = 'Send as keys';

		const inputWrapper = GoogMoreBox.wrap('p', [input, sendButton], moreBox);
		sendButton.onclick = () => {
			if (input.value) {
				client.sendMessage(new TextControlMessage(input.value));
			}
		};

		const commands : HTMLElement[] = [];
		const codes = CommandControlMessage.Commands;
		for (const [action, command] of codes.entries()) {
			const btn = document.createElement('button');
			let bitrateInput : HTMLInputElement;
			let maxFpsInput : HTMLInputElement;
			let iFrameIntervalInput : HTMLInputElement;
			let maxWidthInput : HTMLInputElement;
			let maxHeightInput : HTMLInputElement;
			if (action === ControlMessage.TYPE_CHANGE_STREAM_PARAMETERS) {
				const spoiler = document.createElement('div');
				const spoilerLabel = document.createElement('label');
				const spoilerCheck = document.createElement('input');

				const innerDiv = document.createElement('div');
				const id = `spoiler_video_${udid}_${playerName}_${displayId}_${action}`;

				spoiler.className = 'spoiler';
				spoilerCheck.type = 'checkbox';
				spoilerCheck.id = id;
				spoilerLabel.htmlFor = id;
				spoilerLabel.innerText = command;
				innerDiv.className = 'box';
				spoiler.appendChild(spoilerCheck);
				spoiler.appendChild(spoilerLabel);
				spoiler.appendChild(innerDiv);

				const bitrateLabel = document.createElement('label');
				bitrateLabel.innerText = 'Bitrate:';
				bitrateInput = document.createElement('input');
				bitrateInput.placeholder = `${preferredSettings.bitrate} bps`;
				bitrateInput.value = videoSettings.bitrate.toString();
				GoogMoreBox.wrap('div', [bitrateLabel, bitrateInput], innerDiv);
				this.bitrateInput = bitrateInput;

				const maxFpsLabel = document.createElement('label');
				maxFpsLabel.innerText = 'Max fps:';
				maxFpsInput = document.createElement('input');
				maxFpsInput.placeholder = `${preferredSettings.maxFps} fps`;
				maxFpsInput.value = videoSettings.maxFps.toString();
				GoogMoreBox.wrap('div', [maxFpsLabel, maxFpsInput], innerDiv);
				this.maxFpsInput = maxFpsInput;

				const iFrameIntervalLabel = document.createElement('label');
				iFrameIntervalLabel.innerText = 'I-Frame Interval:';
				iFrameIntervalInput = document.createElement('input');
				iFrameIntervalInput.placeholder = `${preferredSettings.iFrameInterval} seconds`;
				iFrameIntervalInput.value = videoSettings.iFrameInterval.toString();
				GoogMoreBox.wrap('div', [iFrameIntervalLabel, iFrameIntervalInput], innerDiv);
				this.iFrameIntervalInput = iFrameIntervalInput;

				const { width, height } = videoSettings.bounds || client.getMaxSize() || GoogMoreBox.defaultSize;
				const pWidth = preferredSettings.bounds?.width || width;
				const pHeight = preferredSettings.bounds?.height || height;

				const maxWidthLabel = document.createElement('label');
				maxWidthLabel.innerText = 'Max width:';
				maxWidthInput = document.createElement('input');
				maxWidthInput.placeholder = `${pWidth} px`;
				maxWidthInput.value = width.toString();
				GoogMoreBox.wrap('div', [maxWidthLabel, maxWidthInput], innerDiv);
				this.maxWidthInput = maxWidthInput;

				const maxHeightLabel = document.createElement('label');
				maxHeightLabel.innerText = 'Max height:';
				maxHeightInput = document.createElement('input');
				maxHeightInput.placeholder = `${pHeight} px`;
				maxHeightInput.value = height.toString();
				GoogMoreBox.wrap('div', [maxHeightLabel, maxHeightInput], innerDiv);
				this.maxHeightInput = maxHeightInput;

				innerDiv.appendChild(btn);
				const fitButton = document.createElement('button');
				fitButton.innerText = 'Fit';
				fitButton.onclick = this.fit;
				innerDiv.insertBefore(fitButton, innerDiv.firstChild);
				const resetButton = document.createElement('button');
				resetButton.innerText = 'Reset';
				resetButton.onclick = this.reset;
				innerDiv.insertBefore(resetButton, innerDiv.firstChild);
				commands.push(spoiler);
			} else {
				if (
					action === CommandControlMessage.TYPE_SET_CLIPBOARD ||
					action === CommandControlMessage.TYPE_GET_CLIPBOARD
				) {
					inputWrapper.appendChild(btn);
				} else {
					commands.push(btn);
				}
			}
			btn.innerText = command;
			if (action === ControlMessage.TYPE_CHANGE_STREAM_PARAMETERS) {
				btn.onclick = () => {
					const bitrate = parseInt(bitrateInput.value, 10);
					const maxFps = parseInt(maxFpsInput.value, 10);
					const zoomsize = 0.4
					const iFrameInterval = parseInt(iFrameIntervalInput.value, 10);
					if (isNaN(bitrate) || isNaN(maxFps)) {
						return;
					}
					const width = parseInt(maxWidthInput.value, 10) & ~15;
					const height = parseInt(maxHeightInput.value, 10) & ~15;
					const bounds = new Size(width, height);
					const current = player.getVideoSettings();
					const { lockedVideoOrientation, sendFrameMeta, displayId, codecOptions, encoderName } = current;
					const videoSettings = new VideoSettings({
						bounds,
						bitrate,
						maxFps,
						zoomsize,
						iFrameInterval,
						lockedVideoOrientation,
						sendFrameMeta,
						displayId,
						codecOptions,
						encoderName,
					});
					client.sendNewVideoSetting(videoSettings);
				};
			} else if (action === CommandControlMessage.TYPE_SET_CLIPBOARD) {
				btn.onclick = () => {
					const text = input.value;
					if (text) {
						client.sendMessage(CommandControlMessage.createSetClipboardCommand(text));
					}
				};
			} else {
				btn.onclick = () => {
					client.sendMessage(new CommandControlMessage(action));
				};
			}
		}
		GoogMoreBox.wrap('p', commands, moreBox);
		const screenPowerModeId = `screen_power_mode_${udid}_${playerName}_${displayId}`;
		const screenPowerModeLabel = document.createElement('label');
		screenPowerModeLabel.style.display = 'none';
		const labelTextPrefix = 'Mode';
		const buttonTextPrefix = 'Set screen power mode';
		const screenPowerModeCheck = document.createElement('input');
		screenPowerModeCheck.type = 'checkbox';
		let mode = (screenPowerModeCheck.checked = false) ? 'ON' : 'OFF';
		screenPowerModeCheck.id = screenPowerModeLabel.htmlFor = screenPowerModeId;
		screenPowerModeLabel.innerText = `${labelTextPrefix} ${mode}`;
		screenPowerModeCheck.onchange = () => {
			mode = screenPowerModeCheck.checked ? 'ON' : 'OFF';
			screenPowerModeLabel.innerText = `${labelTextPrefix} ${mode}`;
			sendScreenPowerModeButton.innerText = `${buttonTextPrefix} ${mode}`;
		};
		const sendScreenPowerModeButton = document.createElement('button');
		sendScreenPowerModeButton.innerText = `${buttonTextPrefix} ${mode}`;
		sendScreenPowerModeButton.onclick = () => {
			const message = CommandControlMessage.createSetScreenPowerModeCommand(screenPowerModeCheck.checked);
			client.sendMessage(message);
		};
		GoogMoreBox.wrap('p', [screenPowerModeCheck, screenPowerModeLabel, sendScreenPowerModeButton], moreBox, [
			'flex-center',
		]);

		const qualityId = `show_video_quality_${udid}_${playerName}_${displayId}`;
		const qualityLabel = document.createElement('label');
		const qualityCheck = document.createElement('input');
		qualityCheck.type = 'checkbox';
		qualityCheck.checked = BasePlayer.DEFAULT_SHOW_QUALITY_STATS;
		qualityCheck.id = qualityId;
		qualityLabel.htmlFor = qualityId;
		qualityLabel.innerText = 'Show quality stats';
		GoogMoreBox.wrap('p', [qualityCheck, qualityLabel], moreBox, ['flex-center']);
		qualityCheck.onchange = () => {
			player.setShowQualityStats(qualityCheck.checked);
		};

		const stop = (ev ?: string | Event) => {
			if (ev && ev instanceof Event && ev.type === 'error') {
				console.error(TAG, ev);
			}
			const parent = moreBox.parentElement;
			if (parent) {
				parent.removeChild(moreBox);
			}
			player.off('video-view-resize', this.onViewVideoResize);
			if (this.onStop) {
				this.onStop();
				delete this.onStop;
			}
		};

		const stopBtn = document.createElement('button') as HTMLButtonElement;
		stopBtn.innerText = `Disconnect`;
		stopBtn.onclick = stop;

		GoogMoreBox.wrap('p', [stopBtn], moreBox);
		player.on('video-view-resize', this.onViewVideoResize);
		player.on('video-settings', this.onVideoSettings);
		this.holder = moreBox;
	}

	private onViewVideoResize = (size : Size) : void => {
		// padding: 10px
		this.holder.style.width = `${size.width - 2 * 10}px`;
	};

	private onVideoSettings = (videoSettings : VideoSettings) : void => {
		if (this.bitrateInput) {
			this.bitrateInput.value = videoSettings.bitrate.toString();
		}
		if (this.maxFpsInput) {
			this.maxFpsInput.value = videoSettings.maxFps.toString();
		}
		if (this.iFrameIntervalInput) {
			this.iFrameIntervalInput.value = videoSettings.iFrameInterval.toString();
		}
		if (videoSettings.bounds) {
			const { width, height } = videoSettings.bounds;
			if (this.maxWidthInput) {
				this.maxWidthInput.value = width.toString();
			}
			if (this.maxHeightInput) {
				this.maxHeightInput.value = height.toString();
			}
		}
	};

	private fit = () : void => {
		const { width, height } = this.client.getMaxSize() || GoogMoreBox.defaultSize;
		if (this.maxWidthInput) {
			this.maxWidthInput.value = width.toString();
		}
		if (this.maxHeightInput) {
			this.maxHeightInput.value = height.toString();
		}
	};

	private reset = () : void => {
		const preferredSettings = this.player.getPreferredVideoSetting();
		this.onVideoSettings(preferredSettings);
	};

	public async OnDeviceMessage(ev : DeviceMessage) : Promise<void> {
		if (ev.type !== DeviceMessage.TYPE_CLIPBOARD) {
			return;
		}
		const clipboardContent = ev.getText();
		if (!clipboardContent) {
			return;
		}
		if (!navigator.clipboard) {
			this.copyWithExecCommand(clipboardContent); // 调用上面的传统方法
			return;
		}
		try {
			await navigator.clipboard.writeText(clipboardContent);
			console.log(clipboardContent);
		} catch (err) {
			// 失败降级：改用传统方法
			this.copyWithExecCommand(clipboardContent);
		}
	}
	// 封装传统方法作为降级方案
	private copyWithExecCommand(content : string) : void {
		const input = this.input;
		input.value = content;
		input.focus();
		input.select();
		try {
			const isSuccess = document.execCommand('copy');
		} catch (err) {}
	}
	private static wrap(
		tagName : string,
		elements : HTMLElement[],
		parent : HTMLElement,
		opt_classes ?: string[],
	) : HTMLElement {
		const wrap = document.createElement(tagName);
		if (opt_classes) {
			wrap.classList.add(...opt_classes);
		}
		elements.forEach((e) => {
			wrap.appendChild(e);
		});
		parent.appendChild(wrap);
		return wrap;
	}

	public getHolderElement() : HTMLElement {
		return this.holder;
	}

	public setOnStop(listener : () => void) : void {
		this.onStop = listener;
	}
}